#pragma once
#include <GL/glew.h>

#include "../../renderer/volumerenderplugin.h"
#include "../../renderer/GLSLProgram.h"
#include "../../renderer/colormap.h"

namespace PBVP {
	class Reg3DVolumeDataNode;
	class Reg3DVolumeData;
	class GeometryDataNode;
	///
	class VolumeRenderer : public QObject, public VolumeRenderPlugin
	{
		Q_OBJECT
		Q_INTERFACES(PBVP::RenderPlugin)

	public:
		/// Constructor
		VolumeRenderer();
		/// Destructor
		virtual ~VolumeRenderer();

		virtual QString name() const {
			return QString("Volume Renderer");
		}

		virtual QString description() const {
			return QString("3D Texture Based Volume Rendering");
		}
		/**
		*	call this method when the plugin is being activated,
		*	either during startup or at any other time
		*/
		virtual void initialize(MainInterface *mainInterface);
		///
		virtual RenderPlugin* clone();
		/**
		* This function sets up rendering attributes before each rendering
		*/
		virtual void begin();
		
		/// End the rendering of the current Renderer
		virtual void end();
		
		/// Return the control widget of the renderer
		virtual QWidget * getRenderControl() const;
		
		/**
		* If it returns false, this plugin should not be loaded
		*/
		virtual bool initRender();

		/// Is given data type supported by the renderer
		virtual bool isSupported(DataInterface *pData) const;
		
		/// Rendering function
		virtual void render(DataNode *pDataNode);
		
		///
		virtual void setDataNode(DataNode *pDataNode);
		
		/// Reset all default settings
		virtual void reset();

	protected:
		friend	class VolumeRenderControl;

		float funcMin, funcMax;

		void loadColormapTexture(unsigned char* cmapTexture, int size);
		
		/// Compute the bounding box of a volume under viewing transformation
		AxisAlignedBox getBoundingBoxTransformed(const Matrix4& viewMat, const AxisAlignedBox& bbox);

		/// Construct an isocontour at isoval and add it to the data manager
		GeometryDataNode* addContour(double isoval);

		/// Update the isocontour with a new isovalue
		bool updateContour(GeometryDataNode *pGeoNode, double isoval);

		/// Delete an isocontour from the data manager
		bool deleteContour(GeometryDataNode *pGeoNode);

	public slots:
		///
		void updateView();
		
		/// Change volume rendering quality (slices) using slider
		
		void changeQuality(int nSlices);
		
		/// 
		void setShowVolume(int state);
		
		/// 
		void setShowBBox(int state);

	protected:
		GLuint m_DataTexture;
		GLuint m_ColormapTexture;

		bool m_ShowBBox;
		bool m_ShowVolume;

		int m_NSlices;

		/// Dimension of the 3D texture
		unsigned int m_Dim[3];
		/// 3D texture data
		unsigned char *m_pUCData;

		/// 1D Colormap
		ColorMap m_Colormap;

		/// 
		Reg3DVolumeDataNode *m_pVolNode;
		Reg3DVolumeData *m_pVolData;

		counted_ptr<GLSLProgram> m_pProgram;

		VolumeRenderControl *m_VolRendControl;
	};
}